package com.seed.util;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.row.Row;

import java.util.*;

@SuppressWarnings("unchecked")
public class RowKit {

    /**
     * 获取深度ID列表
     * @param rootList 根对象列表
     * @param basePath self对象相对于根对象的路径
     * @param property self对象的属性
     * @return ID列表
     */
    public static <T> List<T> getSelfValues(List<?> rootList, String basePath, String property) {
        return getSelfValues(getSelfList(rootList, basePath), property);
    }

    public static <T> List<T> getSelfValues(List<?> selfList, String property) {
        List<T> ret = new ArrayList<>();
        for(Object self: selfList) {
            T selfValue = getSelfValue(self, property);
            if(selfValue != null) ret.add(selfValue);
        }

        return ret;
    }

    public static <T> T getSelfValue(Object root, String basePath, String property) {
        Object self = getSelf(root, basePath.split("\\."));
        return getSelfValue(self, property);
    }

    public static <T> T getSelfValue(Object self, String property) {
        if(self instanceof Row row) return (T) row.get(property);
        if(self instanceof Map<?,?> map) return (T) map.get(property);

        return (T) ReflectUtil.getFieldValue(self, property);
    }

    public static void setSelfValue(Object self, String property, Object value) {
        if(self instanceof Row row) {
            row.set(property, value);
        } else if(self instanceof LinkedHashMap map) {
            map.put(property, value);
        } else {
            setFieldValue(self, property, value);
        }
    }

    public static <T> List<T> getSelfList(List<?> rootList, String basePath) {
        if(rootList == null || rootList.isEmpty()) return Collections.emptyList();

        if(StrUtil.isBlank(basePath)) return (List<T>) rootList;

        List<T> ret = new ArrayList<>();
        String[] paths = basePath.split("\\.");
        for(Object root: rootList) {
            T self = getSelf(root, paths);
            if(self != null) ret.add(self);
        }

        return ret;
    }

    /**
     * 根据根对象获取self对象
     * @param root 根对象
     * @param paths self对象所在路径分隔后的数组，如：user.organization.roles分隔之后： [user, organization, roles]
     * @return self对象
     */
    public static <T> T getSelf(Object root, String... paths) {
        if(root == null) return null;
        if(paths == null || paths.length == 0) return (T) root;

        if(root instanceof Row rootRow) {
            Row tmp = rootRow;
            for (String path: paths) {
                String fieldName = StrUtil.toCamelCase(path);
                tmp = (Row) tmp.get(fieldName);
                if(tmp == null) return null;
            }
            return (T) tmp;
        }

        Object tmp = root;
        for (String path: paths) {
            String fieldName = StrUtil.toCamelCase(path);
            tmp = ReflectUtil.getFieldValue(tmp, fieldName);
            if(tmp == null) return null;
        }
        return (T) tmp;
    }

    public static <T> T getDeepId(Object self, String path, String property) {
        if(self instanceof Row row) return getRowDeepId(row, path, property);

        return getObjectDeepId(self, path, property);
    }

    private static <T> T getRowDeepId(Row row, String path, String property) {
        String[] items = path.split("\\.");
        Map<String, Object> map = row;
        for(String item: items) {
            map = (Map<String, Object>) map.get(item);
        }
        if(map == null) return null;

        return (T) map.get(property);
    }

    public static Map<String, Object> get(Row row, String path) {
        String[] items = path.split("\\.");
        Map<String, Object> map = row;
        for(String item: items) map = (Map<String, Object>) map.get(item);
        return map;
    }

    private static <T> T getObjectDeepId(Object self, String path, String property) {
        String[] items = path.split("\\.");

        Object tmp = self;
        for(String item: items) tmp = getFieldValue(tmp, item);
        if(tmp == null) return null;

        return getFieldValue(tmp, property);
    }

    public static Row toCamelKeys(Row row) {
        Row ret = new Row();
        ret.putAll(row.toCamelKeysMap());
        return ret;
    }

    public static List<Row> toCamelKeys(List<Row> rows) {
        return rows.stream().map(RowKit::toCamelKeys).toList();
    }

    public static Page<Row> toCamelKeys(Page<Row> page) {
        page.setRecords(toCamelKeys(page.getRecords()));
        return page;
    }

    public static Row toUnderlineKeys(Row row) {
        Row ret = new Row();
        ret.putAll(row.toUnderlineKeysMap());
        return ret;
    }

    public static Row toRow(Map<String, Object> map) {
        Row ret = new Row();
        ret.putAll(map);
        return ret;
    }

    public static List<Row> toRows(List<Map<String, Object>> list) {
        return list.stream().map(e -> toRow(e)).toList();
    }

    public static <T> T getFieldValue(Object obj, String fieldName) {
        return (T) ReflectUtil.getFieldValue(obj, fieldName);
    }

    public static void setFieldValue(Object obj, String fieldName, Object value) {
        ReflectUtil.setFieldValue(obj, fieldName, value);
    }
}
